﻿using System.Linq;
using SPR.Lists;
using Styx;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

using TreeSharp;

namespace SPR.Helpers
{
    using Styx.Combat.CombatRoutine;

    using Action = TreeSharp.Action;

    public class Item
    {
        /* putting all the Item logic here */

        private static readonly Item ItemInstance = new Item();

        /// <summary>
        /// An instance of the Unit Class
        /// </summary>
        public static Item Instance { get { return ItemInstance; } }

        private static LocalPlayer Me
        {
            get { return StyxWoW.Me; }
        }

        /// <summary>
        /// Checks the number of Tier pieces a player is wearing
        /// </summary>
        /// <param name="txxItemSetId">The Tier set ID</param>
        /// <returns>The total Number of Tier pieces</returns>
        private static int NumTierPieces(int txxItemSetId)
        {
            {
                int
                count = Me.Inventory.Equipped.Hands.ItemInfo.ItemSetId == txxItemSetId ? 1 : 0;
                count += Me.Inventory.Equipped.Legs.ItemInfo.ItemSetId == txxItemSetId ? 1 : 0;
                count += Me.Inventory.Equipped.Chest.ItemInfo.ItemSetId == txxItemSetId ? 1 : 0;
                count += Me.Inventory.Equipped.Shoulder.ItemInfo.ItemSetId == txxItemSetId ? 1 : 0;
                count += Me.Inventory.Equipped.Head.ItemInfo.ItemSetId == txxItemSetId ? 1 : 0;
                return count;
            }
        }

        /// <summary>Returns true if player has 2pc Tier set Bonus</summary>
        /// <param name="txxItemSetId">The txx Item Set Id.</param>
        /// <returns>The has 2 pc teir bonus.</returns>
        public bool Has2PcTeirBonus(int txxItemSetId)
        {
            {
                return NumTierPieces(txxItemSetId) >= 2;
            }
        }

        /// <summary>Returns true if player has 4pc Tier set Bonus</summary>
        /// <param name="txxItemSetId">The txx Item Set Id.</param>
        /// <returns>The has 4 pc teir bonus.</returns>
        public bool Has4PcTeirBonus(int txxItemSetId)
        {
            {
                return NumTierPieces(txxItemSetId) == 4;
            }
        }

        /// <summary>Runs Lua MacroText</summary>
        /// <param name="macro">the macro text to run</param>
        /// <param name="cond">The conditions that must be true</param>
        /// <param name="label">A descriptive label for the clients GUI logging output</param>
        /// <returns>The run macro text.</returns>
        public Composite RunMacroText(string macro, CanRunDecoratorDelegate cond, string label)
        {
            return new Decorator(
                cond,
                new Sequence(
                    new Action(a => SPR.Instance.Log(" [RunMacro] {0} ", label)),
                    new Action(a => Lua.DoString("RunMacroText(\"" + Spell.RealLuaEscape(macro) + "\")"))));
        }

        /// <summary>Attempts to use the bag item provided it is usable and its not on cooldown</summary>
        /// <param name="name">the name of the bag item to use</param>
        /// <param name="cond">The conditions that must be true</param>
        /// <param name="label">A descriptive label for the clients GUI logging output</param>
        /// <returns>The use bag item.</returns>
        public Composite UseBagItem(string name, CanRunDecoratorDelegate cond, string label)
        {
            WoWItem item = null;
            return new Decorator(
                delegate(object a)
                    {
                        if (!cond(a))
                            return false;
                        item = Me.BagItems.FirstOrDefault(x => x.Name == name && x.Usable && x.Cooldown <= 0);
                        return item != null;
                    },
                new Sequence(
                    new Action(a => SPR.Instance.Log(" [BagItem] {0} ", label)),
                    new Action(a => item.UseContainerItem())));
        }

        /// <summary>
        /// Returns true if the trinkets conditions are met
        /// </summary>
        /// <param name="trinket">the trinket to check for</param>
        /// <returns>true if we can use the trinket</returns>
        private static bool TrinketUsageSatisfied(WoWItem trinket)
        {
            if (trinket != null)
            {
                switch (trinket.Name)
                {
                    case "Apparatus of Khaz'goroth":
                        return StyxWoW.Me.ActiveAuras["Titanic Power"].StackCount == 5;
                    case "Fury of Angerforge":
                        return StyxWoW.Me.ActiveAuras["Raw Fury"].StackCount == 5;
                    case "Scales of Life":
                        return Buff.PlayerHasBuff("Weight of a Feather") && Me.HealthPercent <= 90;
                    case "Moonwell Phial":
                        return !Me.CurrentTarget.IsMoving && !Me.IsMoving && Me.HealthPercent <= 90;
                    case "Rotting Skull":
                        if (Me.Class == WoWClass.Warrior) return Buff.PlayerCountBuff("Slaughter") == 3;
                        return true;
                    default:
                        return true;
                }
            }
            
            return false;
        }


        /// <summary>
        ///  Blows your wad all over the floor
        /// </summary>
        /// <returns>Nothing but win</returns>
        public static Composite UseTrinkets()
        {
            return new PrioritySelector(delegate
            {
                foreach (WoWItem trinket in Trinkets.CurrentTrinkets.Where(trinket => CanUseEquippedItem(trinket) && TrinketUsageSatisfied(trinket)))
                {
                    SPR.Instance.Log(" [Trinket] {0} ", trinket.Name);
                    trinket.Use();
                } 

                return RunStatus.Success;
            });
        }
        /// <summary>Attempts to use the equipped item (such as trinkets)</summary>
        /// <param name="item">The item.</param>
        /// <param name="cond">The conditions that must be true</param>
        /// <param name="label">A descriptive label for the clients GUI logging output</param>
        /// <returns>The use equipped item.</returns>
        private static Composite UseEquippedItem(WoWItem item, CanRunDecoratorDelegate cond, string label)
        {
            return new Decorator(
                a => cond(a) && CanUseEquippedItem(item),
                new Sequence(
                    new Action(a => SPR.Instance.Log(" [EquipedItem] {0} ", label)),
                    new Action(a => item.Use())));
        }
       

        /// <summary>
        /// Returns true if the equipped item is usable.
        /// </summary>
        /// <param name="item">the item to check</param>
        /// <returns>true if its usable</returns>
        private static bool CanUseEquippedItem(WoWItem item)
        {
            string itemSpell;

            try
            {
                itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            }
            catch (System.NullReferenceException)
            {
                itemSpell = null;
            }
            catch (System.Reflection.TargetInvocationException)
            {
                itemSpell = null;
            }
            catch (InvalidObjectPointerException)
            {
                itemSpell = null;
            }
            catch (System.InvalidOperationException)
            {
                itemSpell = null;
            }

            if (string.IsNullOrEmpty(itemSpell)) return false; // Check for engineering tinkers!
            if (Me.BagItems.Any(x => x.ItemInfo.Id == item.ItemInfo.Id)) return false; // if its in our bag then gtfo

            return item.Usable && item.Cooldown <= 0;
        }

        /// <summary>
        /// Uses the players engineering gloves provided the player has engineering gloves
        /// and the engineering gloves are not on cooldown and the engineering gloves are usable.
        /// </summary>
        /// <param name="cond">The conditions that must be true</param>
        /// <param name="label">A descriptive label for the clients GUI logging output</param>
        /// <returns>true or false</returns>
        public Composite UseEngineerGloves(CanRunDecoratorDelegate cond, string label)
        {
            return UseEquippedItem(Me.Inventory.GetItemBySlot(10), cond, label);
        }

        /// <summary>Returns true if the player has a mana gem in his bag.</summary>
        /// <returns>The have mana gem.</returns>
        public bool HaveManaGem()
        {
            return ObjectManager.GetObjectsOfType<WoWItem>(false).Any(item => item.Entry == 36799);
        }

        // internal static bool Keypresser()
        // {
        //    bool IsLeftAltKeyDown = Lua.GetReturnVal<bool>("if IsLeftAltKeyDown() and GetCurrentKeyBoardFocus() == nil then return true end", 0);
        //    return IsLeftAltKeyDown;
        // }
    }
}
